package util;

import org.apache.commons.lang.StringUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;

public class DateUtils {
    public static final String DATE_FORMAT_FULL = "yyyy-MM-dd HH:mm:ss";
    public static final String DATE_FORMAT_YMD = "yyyy-MM-dd";
    public static final String DATE_FORMAT_SHORT_YMD = "yyyyMMdd";
    public static final String DATE_FORMAT_CH_YMD = "yyyy年MM月dd日";
    public static final String DATE_FORMAT_HMS = "HH:mm:ss";
    public static final String DATE_FORMAT_HM = "HH:mm";
    public static final String DATE_FORMAT_YMDHM = "yyyy-MM-dd HH:mm";
    public static final String DATE_FORMAT_YMDHMS = "yyyyMMddHHmmss";
    public static final long ONE_DAY_MILLS = 86400000L;
    public static final int WEEK_DAYS = 7;
    private static final Object lockObj = new Object();
    private static Map<String, ThreadLocal<SimpleDateFormat>> sdfMap = new HashMap();

    public DateUtils() {
    }

    private static SimpleDateFormat getSdf(final String pattern) {
        ThreadLocal<SimpleDateFormat> tl = (ThreadLocal)sdfMap.get(pattern);
        if (tl == null) {
            synchronized(lockObj) {
                tl = (ThreadLocal)sdfMap.get(pattern);
                if (tl == null) {
                    tl = new ThreadLocal<SimpleDateFormat>() {
                        protected SimpleDateFormat initialValue() {
                            return new SimpleDateFormat(pattern);
                        }
                    };
                    sdfMap.put(pattern, tl);
                }
            }
        }

        return (SimpleDateFormat)tl.get();
    }

    public static String formatDateToString(Date date, String pattern) {
        return date == null ? null : getSdf(pattern).format(date);
    }

    public static Date formatStringToDate(String dateStr, String pattern) {
        if (StringUtils.isBlank(dateStr)) {
            return null;
        } else {
            try {
                return getSdf(pattern).parse(dateStr);
            } catch (ParseException var3) {
                return null;
            }
        }
    }

    public static boolean isTimeInRange(Date time, Date[] timeRange) {
        return !time.before(timeRange[0]) && !time.after(timeRange[1]);
    }

    public static void main(String[] args) {
        System.out.println(isTimeInRange(new Date(), "22:00", "05:00", "HH:mm", "GMT+08"));
        System.out.println(isTimeInRange(new Date(), "2022-11-16 18:00", "2022-11-17 05:00", "yyyy-MM-dd HH:mm", "GMT+08"));
    }

    public static boolean isTimeInRange(Date now, String startTime, String endTime, String pattern, String timezone) {
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        TimeZone timeZone = TimeZone.getTimeZone(timezone);
        sdf.setTimeZone(timeZone);
        Date date = formatStringToDate(sdf.format(now), pattern);
        Date start = formatStringToDate(startTime, pattern);
        Date end = formatStringToDate(endTime, pattern);
        if (!start.after(end) && !start.equals(end)) {
            if (date.getTime() >= start.getTime() && date.getTime() <= end.getTime()) {
                return true;
            }
        } else if (date.getTime() >= start.getTime() || date.getTime() <= end.getTime()) {
            return true;
        }

        return false;
    }

    public static int getDaysBetween(String startDate, String endDate) throws ParseException {
        int dayGap = 0;
        if (startDate != null && startDate.length() > 0 && endDate != null && endDate.length() > 0) {
            Date end = formatStringToDate(endDate, "yyyy-MM-dd");
            Date start = formatStringToDate(startDate, "yyyy-MM-dd");
            dayGap = getDaysBetween(start, end);
        }

        return dayGap;
    }

    public static int getDaysBetween(Date startDate, Date endDate) {
        return (int)((endDate.getTime() - startDate.getTime()) / 86400000L);
    }

    public static int getDaysGapOfDates(Date startDate, Date endDate) {
        int date = 0;
        if (startDate != null && endDate != null) {
            date = getDaysBetween(startDate, endDate);
        }

        return date;
    }

    public static int getYearGapOfDates(Date firstDate, Date secondDate) {
        if (firstDate != null && secondDate != null) {
            Calendar helpCalendar = Calendar.getInstance();
            helpCalendar.setTime(firstDate);
            int firstYear = helpCalendar.get(1);
            helpCalendar.setTime(secondDate);
            int secondYear = helpCalendar.get(1);
            return secondYear - firstYear;
        } else {
            return 0;
        }
    }

    public static int getMonthGapOfDates(Date firstDate, Date secondDate) {
        return firstDate != null && secondDate != null ? (int)((secondDate.getTime() - firstDate.getTime()) / 86400000L / 30L) : 0;
    }

    public static boolean isContainCurrent(List<String> dates) {
        boolean flag = false;
        SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
        Date date = new Date();
        String dateStr = fmt.format(date);

        for(int i = 0; i < dates.size(); ++i) {
            if (dateStr.equals(dates.get(i))) {
                flag = true;
            }
        }

        return flag;
    }

    public static String getCalculateDateToString(String startDate, int time) throws ParseException {
        String resultDate = null;
        if (startDate != null && startDate.length() > 0) {
            Date date = formatStringToDate(startDate, "yyyy-MM-dd");
            Calendar c = Calendar.getInstance();
            c.setTime(date);
            c.set(6, time);
            date = c.getTime();
            resultDate = formatDateToString(date, "yyyy-MM-dd");
        }

        return resultDate;
    }

    public static Date addDays(Date date, int amount) {
        return add(date, 5, amount);
    }

    public static Date add(Date date, int calendarField, int amount) {
        if (date == null) {
            throw new IllegalArgumentException("The date must not be null");
        } else {
            Calendar c = Calendar.getInstance();
            c.setTime(date);
            c.add(calendarField, amount);
            return c.getTime();
        }
    }

    public static Date getCurDateStartTime() {
        Calendar c = Calendar.getInstance();
        c.set(11, 0);
        c.set(12, 0);
        c.set(13, 0);
        c.set(14, 0);
        return c.getTime();
    }

    public static Date getCurDateEndTime() {
        Calendar c = Calendar.getInstance();
        c.set(11, 23);
        c.set(12, 59);
        c.set(13, 59);
        return c.getTime();
    }

    public static Date getStartTime(Date date) {
        Calendar curr = Calendar.getInstance();
        curr.setTime(date);
        curr.set(11, 0);
        curr.set(12, 0);
        curr.set(13, 0);
        curr.set(14, 0);
        return curr.getTime();
    }

    public static Date getEndTime(Date date) {
        Calendar curr = Calendar.getInstance();
        curr.setTime(date);
        curr.set(11, 23);
        curr.set(12, 59);
        curr.set(13, 59);
        return curr.getTime();
    }

    public static int getWeekOfDate(String datetime) throws ParseException {
        Calendar cal = Calendar.getInstance();
        cal.setFirstDayOfWeek(2);
        cal.setMinimalDaysInFirstWeek(7);
        Date date = formatStringToDate(datetime, "yyyy-MM-dd");
        cal.setTime(date);
        return cal.get(7);
    }

    public static String getDistanceTime(long time) {
        long day = time / 86400000L;
        long hour = time / 3600000L - day * 24L;
        long min = time / 60000L - day * 24L * 60L - hour * 60L;
        long sec = time / 1000L - day * 24L * 60L * 60L - hour * 60L * 60L - min * 60L;
        StringBuilder sb = new StringBuilder();
        if (day > 0L) {
            sb.append(day).append("天");
        }

        if (hour > 0L) {
            sb.append(hour).append("时");
        }

        if (min > 0L) {
            sb.append(min).append("分");
        }

        if (sec > 0L) {
            sb.append(sec).append("秒");
        }

        return sb.toString();
    }
}